<template>
  <div class="box">
    <!-- <h1>用户管理</h1> -->
    <el-card>
      <el-form inline class="inlineForm" style="height: 90px;">
        <el-form-item label="用户名：">
          <el-input placeholder="请输入需要搜索的用户名" v-model="keywordThatUsedToSearchUsername"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" size="default" :disabled="keywordThatUsedToSearchUsername ? false : true"
            @click="handlerForUserClickSearchButton">搜索</el-button>
          <el-button type="normal" size="default" @click="handlerForUserClickResetButton">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <el-card style="margin: 10px 0px;">
      <!-- 这里是卡片中的占位文字 -->
      <el-button type="primary" size="default" @click="handlerForUserClickTheAddUserButton" v-haveThisButton="`btn.User.add`">添加用户</el-button>
      <el-button type="danger" size="default" :disabled="idListForAlotOfUsersWillBeDeleted.length ? false : true"
        @click="handlerForDeleteAlotOfUsers" v-haveThisButton="`btn.User.remove`">批量删除</el-button>
      <!-- 被用于展示用户信息的表格（注：当“选择项发生变化”时会触发“selection-change”事件）↓ -->
      <el-table border style="margin: 10px 0px;" :data="userList" @selection-change="handlerForSelectionChange">
        <!-- 注：“type="selection"”表示“显示复选框”↓ -->
        <el-table-column type="selection" align="center"></el-table-column>
        <el-table-column label="序号" align="center" type="index" width="60px"></el-table-column>
        <el-table-column label="用户ID" align="center" prop="id"></el-table-column>
        <el-table-column label="用户名字" align="center" prop="username" show-overflow-tooltip></el-table-column>
        <el-table-column label="用户名称" align="center" prop="name" show-overflow-tooltip></el-table-column>
        <el-table-column label="用户职位" align="center" prop="roleName" show-overflow-tooltip></el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime" show-overflow-tooltip></el-table-column>
        <el-table-column label="更新时间" align="center" prop="updateTime" show-overflow-tooltip></el-table-column>
        <el-table-column label="操作" align="center" width="280px">
          <template #default="{ row, $index }">
            <el-button type="primary" size="small" icon="User"
              @click="handlerForUserClickTheAssignPositionButton(row)" v-haveThisButton="`btn.User.assgin`">分配职位</el-button>
            <el-button type="primary" size="small" icon="Edit"
              @click="handlerForUserClickTheEditUserButton(row)" v-haveThisButton="`btn.User.update`">编辑</el-button>
            <el-popconfirm :title="`你确定要删除${row.username}吗？`" width="260px" @confirm="deleteAUser(row.id)">
              <template #reference>
                <el-button type="danger" size="small" icon="Delete" v-haveThisButton="`btn.User.remove`">删除</el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页器↓ -->
      <!-- 注：由于“current-change”事件会向其处理函数传递新的页码作为参数，所以此处可以直接以“getUserInformation”作为“事件处理函数”↓ -->
      <el-pagination @current-change="getUserInformation"
        @size-change="handlerForChangeThePageSizeOfPaginationComponent" v-model:current-page="currentPageNumber"
        v-model:page-size="currentPageSize" :page-sizes="[5, 7, 9, 11]" :background="true"
        layout="prev, pager, next, jumper,->,sizes,total" :total="totalNumberOfUsers" />
    </el-card>
    <!-- 抽屉组件（被用于“添加用户”和“修改用户”）↓ -->
    <el-drawer v-model="isTheDrawerVisible">
      <template #header>
        <!-- <h4>添加用户</h4> -->
        <h4>{{ anObjectThatStoreUserInformation.id ? '修改用户' : '添加用户' }}</h4>
      </template>
      <template #default>
        <el-form label-width="100px" :model="anObjectThatStoreUserInformation" :rules="rules" ref="refForForm">
          <el-form-item label="用户姓名" prop="username">
            <el-input placeholder="请您输入姓名" v-model="anObjectThatStoreUserInformation.username"></el-input>
          </el-form-item>
          <el-form-item label="用户昵称" prop="name">
            <el-input placeholder="请您输入昵称" v-model="anObjectThatStoreUserInformation.name"></el-input>
          </el-form-item>
          <!-- 注：由于在这个项目中“密码”不允许被用户修改，所以在“修改用户”时不显示这个表单项↓ -->
          <el-form-item label="密码" prop="password" v-if="!anObjectThatStoreUserInformation.id">
            <el-input placeholder="请您输入密码" v-model="anObjectThatStoreUserInformation.password"></el-input>
          </el-form-item>
        </el-form>
      </template>
      <template #footer>
        <div style="flex: auto">
          <el-button @click="handlerForUserClickTheCancelButton">取消</el-button>
          <el-button type="primary" @click="handlerForUserClickTheSaveButton">保存</el-button>
        </div>
      </template>
    </el-drawer>
    <!-- 抽屉组件（被用于“为用户分配职位”）↓ -->
    <el-drawer v-model="isTheAnotherDrawerVisible" direction="rtl">
      <template #header>
        <h4>分配职位</h4>
      </template>
      <template #default>
        <el-form>
          <el-form-item label="用户姓名">
            <el-input v-model="anObjectThatStoreUserInformation.name" :disabled="true"></el-input>
          </el-form-item>
          <el-form-item label="职位列表">
            <!-- 注：属性“indeterminate”被用于设置“全选复选框是否处于不确定状态”（但它仅负责样式控制）↓ -->
            <el-checkbox @change="handlerForCheckAllChange" v-model="ifAllOfTheCheckboxAreChecked"
              :indeterminate="isTheCheckboxNamedCheckAllIndeterminateNow">全选</el-checkbox>
            <el-checkbox-group v-model="positionsChoosedByUser" @change="handlerForCheckedPositionsBeChanged">
              <!-- 被用于显示职位的复选框（注：属性“label”的值是“要存储的数据”）↓ -->
              <!-- <el-checkbox v-for="(position,index) in positionList" :key="index" :label="position"> -->
              <el-checkbox v-for="(position, index) in positionList" :key="index" :label="position">
                {{ position.roleName }}
              </el-checkbox>
            </el-checkbox-group>
          </el-form-item>
        </el-form>
      </template>
      <template #footer>
        <div style="flex: auto">
          <el-button @click="isTheAnotherDrawerVisible = false">取消</el-button>
          <el-button type="primary"
            @click="handlerForUserClickTheConfirmButtonInTheDrawerForAssignPositions">确定</el-button>
        </div>
      </template>
    </el-drawer>
  </div>
</template>

<script lang="ts" setup name="User">
import { ref, onMounted, reactive, nextTick } from 'vue'
import {
  requestAllOfUsersInformation,
  requestAddOrUpdateAUser,
  requestAllOfPositionsAndPositionsThatCurrentUserHaveBeenHad,
  requestAssignPositionForAUser,
  requestDeleteAUser,
  requestDeleteALotOfUser,
} from '@/api/acl/user'
import { ElMessage } from 'element-plus'
// 导入并获取布局设置模块的仓库实例↓
import useLayoutSettingStore from '@/store/modules/setting'
let layoutSettingStore = useLayoutSettingStore()
import type {
  typeOfResponseDataOfTheApiThatGetUserList,
  typeOfPropertyNamedRecordsInTheResponseDataOfTheApiThatGetUserList,
  typeOfObjectThatStoreUserInformation,
  typeOfResponseDataOfTheApiThatGetrequestAllOfPositionsAndPositionsThatCurrentUserHaveBeenHad,
  typeOfpositionListThatIncludeAllOfPosition,
  typeOfParamsThatSentToTheApiThatAssignPositionsToAUser,
  typeOfObjectThatRepresentsAPosition,
} from '@/api/acl/user/type'
let keywordThatUsedToSearchUsername = ref<string>('') // 定义一个变量，用以存储用户搜索“用户名”时输入的关键字
let currentPageNumber = ref<number>(1)
let currentPageSize = ref<number>(3)
let totalNumberOfUsers = ref<number>(0)
let userList = ref<typeOfPropertyNamedRecordsInTheResponseDataOfTheApiThatGetUserList>([])
let isTheDrawerVisible = ref<boolean>(false) // 定义一个变量，它被用于控制抽屉组件的显示与隐藏
let isTheAnotherDrawerVisible = ref<boolean>(false) // 定义一个变量，它被用于控制另一个抽屉组件的显示与隐藏
let ifAllOfTheCheckboxAreChecked = ref<boolean>(false) // 定义一个变量，用以控制是否全选复选框
let isTheCheckboxNamedCheckAllIndeterminateNow = ref<boolean>(false) // 定义一个变量，用以控制名为“全选”的复选框是否处于“半选”状态
// let positionList = ref<string[]>(['销售','前台','财务','行政']) // 定义一个变量，用以存储职位列表信息
let positionList = ref<typeOfpositionListThatIncludeAllOfPosition>([])
// let theListOfCurrentUserHaveBeenHad = ref<typeOfpositionListThatIncludeAllOfPosition>([]) // 定义一个变量，用以存储当前用户已被分配的职位信息
let positionsChoosedByUser = ref<typeOfpositionListThatIncludeAllOfPosition>([])
// let positionsChoosedByUser = ref<string[]>(['前台']) // 定义一个变量，用以存储用户选择的职位信息
let anObjectThatStoreUserInformation = reactive<typeOfObjectThatStoreUserInformation>({
  username: '',
  name: '',
  password: '',

})
// 获取表单组件的实例↓
let refForForm = ref<any>()
let idListForAlotOfUsersWillBeDeleted = ref<typeOfObjectThatStoreUserInformation[]>([]) // 定义一个变量，用以存储将要被删除的用户ID列表
/**
 * @description 自定义校验规则函数，用以对用户名的长度进行校验
 * @param rule 自定义校验规则对象
 * @param value 在文本框中输入的值
 * @param callback 在校验规则是否通过时都需要被调用的回调函数（在校验通过时放行，校验不通过时则调用构造函数Error创建一个内含提示信息的错误对象）
 */
function theValidatorForUsername(rule: any, value: string, callback: Function) {
  console.log(value)
  if (value.length >= 5 && value.length <= 10) {
    callback()
  } else {
    callback(new Error('用户名的长度为5到10位'))
  }
}
/**
 * @description 自定义校验规则函数，用于对用户昵称的长度进行校验
 * @param rule 自定义校验规则对象
 * @param value 在文本框中输入的值
 * @param callback 在校验规则是否通过时都需要被调用的回调函数（在校验通过时放行，校验不通过时则调用构造函数Error创建一个内含提示信息的错误对象）
 */
function theValidatorForname(rule: any, value: string, callback: Function) {
  if (value.length >= 5) {
    callback()
  } else {
    callback(new Error('用户昵称长度至少为5位'))
  }
}
/**
 * @description 自定义校验规则函数，用于对密码的长度进行校验
 * @param rule 自定义校验规则对象
 * @param value 在文本框中输入的值
 * @param callback 在校验规则是否通过时都需要被调用的回调函数（在校验通过时放行，校验不通过时则调用构造函数Error创建一个内含提示信息的错误对象）
 */
function theValidatorForPassword(rule: any, value: string, callback: Function) {
  if (value.length >= 6 && value.length <= 15) {
    callback()
  } else {
    callback(new Error('密码的长度为6到15位'))
  }
}
let rules = {
  username: [{ required: true, trigger: 'blur', validator: theValidatorForUsername }],
  name: [{ required: true, trigger: 'blur', validator: theValidatorForname }],
  password: [{ required: true, trigger: 'blur', validator: theValidatorForPassword }],
  // 注：校验规则的触发时机使用“change”时，在重置表单项时由于使用了“空字符串”，不符合校验规则，所以再次打开抽屉时输入框下面仍会显示校验未通过时应显示的提示信息，所以触发时机不能选用“change”↓
  /* username: [{ required: true, trigger: 'change', validator: theValidatorForUsername }],
  name: [{ required: true, trigger: 'change', validator: theValidatorForname }],
  password: [{ required: true, trigger: 'change', validator: theValidatorForPassword }], */
}
// 在组件挂载完毕时调用“getUserInformation”方法，发送请求获取用户信息↓
onMounted(() => {
  getUserInformation() // 未传参时使用“参数默认值”，获取第一页的数据
})

/**
 * 获取用户信息
 */
async function getUserInformation(pageNumber = 1) {
  currentPageNumber.value = pageNumber
  let result: typeOfResponseDataOfTheApiThatGetUserList = await requestAllOfUsersInformation(currentPageNumber.value, currentPageSize.value, keywordThatUsedToSearchUsername.value)
  console.log(result) // {code: 200, message: '成功', data: {…}, ok: true}
  if (result.code == 200) {
    totalNumberOfUsers.value = result.data.total
    userList.value = result.data.records
  }
}
/**
 * @description 处理分页组件的“每页显示条目数”更改事件，用以更新“每页显示条目数”的值。
 * @param newPageSize 新的每页可显示的数据条目
 */
function handlerForChangeThePageSizeOfPaginationComponent(newPageSize: number) {
  console.log(newPageSize)
  getUserInformation() // 未传参时使用“参数默认值”，获取第一页的数据
}
/**
 * @description 处理用户点击“添加用户”按钮时发生的事件
 */
function handlerForUserClickTheAddUserButton() {
  isTheDrawerVisible.value = true // 显示抽屉组件
  Object.assign(anObjectThatStoreUserInformation, {
    username: '',
    name: '',
    password: '',
    id: 0, // 注：为防止用户先点击“编辑”（修改用户）按钮，再点击“添加用户”按钮，导致在收集到用户ID后，因“ID不为空”，使得用户点击“添加用户”按钮时抽屉的标题仍显示为“编辑用户”，所以在此处需要将用户ID清空
  }) // 在每次添加用户前先重置上次操作后残留的表单数据
  // console.log(refForForm.value) // undefined（注：在第一次点击按钮时，由于此时此时DOM还未被渲染完成，所以获取不到表单组件的实例）
  // 使用“nextTick”方法，在DOM渲染完毕，能确保已经获取到更新后的DOM时，再执行回调函数，清除上次操作时，表单校验未通过时残留的错误提示信息↓
  nextTick(() => {
    // console.log(refForForm.value) // Proxy(Object) {validate: ƒ, validateField: ƒ, resetFields: ƒ, clearValidate: ƒ, scrollToField: ƒ, …}
    // 清除指定表单项的校验结果↓
    refForForm.value.clearValidate('username')
    refForForm.value.clearValidate('name')
    refForForm.value.clearValidate('password')
  })
}
/**
 * @description 处理用户点击“编辑”按钮时发生的事件
 * @param row 用户信息对象
 */
function handlerForUserClickTheEditUserButton(row: typeOfObjectThatStoreUserInformation) {
  isTheDrawerVisible.value = true
  /* Object.assign(anObjectThatStoreUserInformation, {
    username: '',
    name: '',
    password: '',
  }) */ // 在每次编辑用户前先重置上次操作后残留的表单数据
  console.log(row) // Proxy(Object) {id: 78311, createTime: '2021-05-31 18:08:43', updateTime: '2024-02-02 08:28:51', username: 'text00100', password: 'e10adc3949ba59abbe56e057f20f883e', …}
  Object.assign(anObjectThatStoreUserInformation, row) // 将用户信息对象中的数据赋值给anObjectThatStoreUserInformation，用以在表单中显示该用户的详细信息
  nextTick(() => {
    /* refForForm.value.clearValidate('username')
    refForForm.value.clearValidate('name')
    refForForm.value.clearValidate('password') */
    refForForm.value.resetFields('username')
    refForForm.value.resetFields('name')
    refForForm.value.resetFields('password')
  })
}
/**
 * @description 处理用户点击“保存”按钮时发生的事件
 */
async function handlerForUserClickTheSaveButton() {
  // 注意：在用户点击保存按钮时，需要保证在所有表单项都校验通过的情况下，才能发起“添加/修改用户”的请求。
  let anotherResult = refForForm.value.validate() // 发起校验操作，该方法会返回一个Promise对象
  console.log(anotherResult) // Promise {<fulfilled>: undefined}

  let result = await requestAddOrUpdateAUser(anObjectThatStoreUserInformation)
  console.log(result) // undefined
  if (result.code == 200) {
    // 如果进入了这个代码块，那么说明“添加/修改用户”操作成功
    isTheDrawerVisible.value = false // 关闭抽屉
    ElMessage({
      type: 'success',
      message: anObjectThatStoreUserInformation.id ? '修改用户成功' : '添加用户成功',
    }) // 注：由于刷新页面后会重新获取用户信息，所以此处不需要再调用“getUserInformation”方法，因此注释下面的这一行代码↓
    // getUserInformation(anObjectThatStoreUserInformation.id?currentPageNumber.value:1) // 获取最新的用户信息，用以更新表格中的数据
    window.location.reload() // 让浏览器在修改用户信息成功后自动刷新页面（以防止出现用户修改自己的用户名后，页面右上角仍显示原有用户名的情况，
    // 并且由于正在登录的用户账号的信息被修改后，浏览器应该跳转到登录页面，让用户重新登录以获取最新的用户信息，所以此处应该让浏览器自动刷新页面，以跳转到登录页）↑
  } else {
    isTheDrawerVisible.value = false
    ElMessage({
      type: 'error',
      message: anObjectThatStoreUserInformation.id ? '修改用户失败' : '添加用户失败',
    })
  }
}
/**
 * @description 处理用户点击“取消”按钮时发生的事件
 */
function handlerForUserClickTheCancelButton() {
  isTheDrawerVisible.value = false
}
/**
 * @description 处理用户点击“分配职位”按钮时发生的事件
 * @param row 用户信息对象
 */
async function handlerForUserClickTheAssignPositionButton(row: typeOfObjectThatStoreUserInformation) {
  // isTheAnotherDrawerVisible.value = true // 显示另一个抽屉组件
  console.log(row) // Proxy(Object) {id: 78318, createTime: '2025-03-17 05:02:38', updateTime: '2025-03-17 05:02:38', username: '11111234', password: 'e10adc3949ba59abbe56e057f20f883e', …}
  Object.assign(anObjectThatStoreUserInformation, row) // 存储用户信息对象中的数据，用以在表单中显示该用户的详细信息
  console.log(anObjectThatStoreUserInformation.id) // 78378
  let result: typeOfResponseDataOfTheApiThatGetrequestAllOfPositionsAndPositionsThatCurrentUserHaveBeenHad = await requestAllOfPositionsAndPositionsThatCurrentUserHaveBeenHad((anObjectThatStoreUserInformation.id as number)) // 获取当前用户已被分配的职位信息，用以在抽屉中显示该用户的已有职位信息
  console.log(result) // {code: 200, message: '成功', data: {…}, ok: true}
  if (result.code == 200) {
    positionList.value = result.data.allRolesList
    // theListOfCurrentUserHaveBeenHad.value = result.data.assignRoles
    positionsChoosedByUser.value = result.data.assignRoles
    isTheAnotherDrawerVisible.value = true
  }
}
/**
 * @description 函数“handlerForCheckAllChange”被用于处理全选框的选中状态被改变时发生的事件
 * @param value 布尔值，表示全选框的选中状态是否发生了改变。true 表示被选中了，false 表示未被选中
 */
function handlerForCheckAllChange(value: boolean) {
  // console.log(isTheCheckboxNamedCheckAllIndeterminateNow.value) // true/false
  console.log(value) // true/false
  positionsChoosedByUser.value = value ? positionList.value : [] // 根据全选框的选中状态，决定是否将所有职位的选择状态设置为true或false
  isTheCheckboxNamedCheckAllIndeterminateNow.value = false
}
/**
 * @description 处理用户选择的职位被改变时发生的事件
 */
// function handlerForCheckedPositionsBeChanged(value:string[]) {
function handlerForCheckedPositionsBeChanged(value: typeOfpositionListThatIncludeAllOfPosition) {
  // console.log('用户选择的职位被改变了')
  console.log(value) // [Proxy(Object), Proxy(Object)]
  const quantityOfPositionsChoosedByUser = value.length // 获取用户选择的职位的数量
  console.log(quantityOfPositionsChoosedByUser) // 2
  ifAllOfTheCheckboxAreChecked.value = quantityOfPositionsChoosedByUser === positionList.value.length // 根据用户选择的职位的数量，决定是否将全选框设置为选中状态
  isTheCheckboxNamedCheckAllIndeterminateNow.value = !(quantityOfPositionsChoosedByUser === positionList.value.length) // 根据用户选择的职位的数量，决定是否将全选框设置为半选中状态
  // 注：此处也可以写为“下面的这一行代码”↓
  // isTheCheckboxNamedCheckAllIndeterminateNow.value = quantityOfPositionsChoosedByUser > 0 && quantityOfPositionsChoosedByUser < positionList.value.length
}
/**
 * @description 处理用户点击“确定”按钮（在被用于“分配职位”的抽屉中）时发生的事件
 */
async function handlerForUserClickTheConfirmButtonInTheDrawerForAssignPositions() {
  let data: typeOfParamsThatSentToTheApiThatAssignPositionsToAUser = {
    roleIdList: positionsChoosedByUser.value.map((item: typeOfObjectThatRepresentsAPosition) => (item.id as number)),
    userId: (anObjectThatStoreUserInformation.id as number),
  }
  console.log(data) // {roleIdList: Array(2), userId: 78390}
  let result: any = await requestAssignPositionForAUser(data)
  console.log(result) // {code: 200, message: '成功', data: null, ok: true}
  if (result.code == 200) {
    ElMessage({
      type: 'success',
      message: '分配职位成功',
    })
    isTheAnotherDrawerVisible.value = false
    getUserInformation(currentPageNumber.value) // 为用户分配职位成功后，需要重新获取用户信息，以更新表格中的数据（注：页码不变，因为“为用户分配职位”属于“更新数据”，数据总数没有发生变动）
  } else {
    ElMessage({
      type: 'error',
      message: '分配职位失败',
    })
  }
}
/**
 * @description 函数“deleteAUser”被用于处理用户点击气泡确认框中的“确认”按钮（它被用于“删除一个用户”）时发生的事件
 */
async function deleteAUser(userId: number) {
  let result: any = await requestDeleteAUser(userId)
  console.log(result) // {code: 200, message: '成功', data: null, ok: true}
  if (result.code == 200) {
    ElMessage({
      type: 'success',
      message: '删除用户成功',
    })
    getUserInformation(userList.value.length > 1 ? currentPageNumber.value : currentPageNumber.value - 1)
  } else {
    ElMessage({
      type: 'error',
      message: '删除用户失败',
    })

  }
}
/**
 * @description 处理用户选择的行被改变时发生的事件（它被用于“批量删除用户”）
 * @param value 被选中的用户信息对象的所在数组
 */
function handlerForSelectionChange(value: typeOfPropertyNamedRecordsInTheResponseDataOfTheApiThatGetUserList) {
  console.log(value) // [Proxy(Object), Proxy(Object)]
  idListForAlotOfUsersWillBeDeleted.value = value
}
/**
 * @description 处理用户点击“批量删除”按钮时发生的事件
 */
async function handlerForDeleteAlotOfUsers() {
  let idList = idListForAlotOfUsersWillBeDeleted.value.map((item: typeOfObjectThatStoreUserInformation) => {
    return item.id
  })
  console.log(idList) // [78356, 78355]
  let result: any = await requestDeleteALotOfUser(idList)
  console.log(result) // {code: 200, message: '成功', data: null, ok: true}
  if (result.code == 200) {
    ElMessage({
      type: 'success',
      message: '删除用户成功',
    })
    getUserInformation(userList.value.length > 1 ? currentPageNumber.value : currentPageNumber.value - 1)
  } else {
    ElMessage({
      type: 'error',
      message: '删除用户失败',
    })

  }
}
/**
 * @description 处理用户点击“搜索”按钮时发生的事件
 */
function handlerForUserClickSearchButton() {
  getUserInformation() // 根据用户在搜索框中输入的关键字来获取与之匹配的用户信息，并在表格中显示这些信息
  keywordThatUsedToSearchUsername.value = '' // 清空搜索框中的内容
}
/**
 * @description 处理用户点击“重置”按钮时发生的事件
 */
function handlerForUserClickResetButton() {
  layoutSettingStore.isThePageBeRefreshed = !layoutSettingStore.isThePageBeRefreshed
}
</script>

<style scoped>
.box {
  width: 100%;
  height: 400px;
  /* background: red; */
}

.inlineForm {
  height: 50px;
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>